package org.exez.modules.visitor.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.exez.common.exception.JeecgBootException;
import org.exez.common.system.vo.LoginUser;
import org.exez.common.util.DateUtils;
import org.exez.modules.system.util.VisitorBeanUtils;
import org.exez.modules.visitor.constant.ApplicationStatusEnum;
import org.exez.modules.visitor.constant.AuthorityEnum;
import org.exez.modules.visitor.constant.IdentityTypeEnum;
import org.exez.modules.visitor.constant.VisitorConstants;
import org.exez.modules.visitor.dto.ReservationApplicationDTO;
import org.exez.modules.visitor.dto.terminal.VisitorReservationDTO;
import org.exez.modules.visitor.entity.*;
import org.exez.modules.visitor.mapper.ReservationApplicationMapper;
import org.exez.modules.visitor.service.*;
import org.exez.modules.visitor.util.*;
import org.exez.modules.visitor.vo.IndexCountVO;
import org.exez.modules.visitor.vo.ReservationApplicationCountVO;
import org.exez.modules.visitor.vo.ReservationApplicationVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * @Description: 访客申请记录表
 * @Author: exez-boot
 * @Date: 2020-06-04
 * @Version: V1.0
 */
@Slf4j
@Service
public class ReservationApplicationServiceImpl extends ServiceImpl<ReservationApplicationMapper, ReservationApplication> implements IReservationApplicationService {
    private static final Integer  ACCOMPANYING_STATUS_YES = 1;

    @Value("${url.mogo-upload}")
    private String uploadUrl;

    @Value("${url.mogo-view}")
    private String fileView;

    /**
     * 西点标识
     */
    private static final Integer DATE_TYPE = 99;

    @Autowired
    private IAccompanyingService accompanyingService;

    @Autowired
    private IVisitTypeService visitTypeService;

    @Autowired
    private IInstitutionService iInstitutionService;

    @Autowired
    private SjyService sjyService;

    @Autowired
    private IVisitorAccessreService visitorAccessreService;


    @Autowired
    private IPushRecordService pushRecordService;

    @Autowired
    private IDeviceService deviceService;

    @Autowired
    private PoliceService policeService;

    @Autowired
    private IKeyPersonnelService keyPersonnelService;

    @Autowired
    private IXdPeopleService xdPeopleService;

    @Autowired
    private IReservationApplicationCopyService reservationApplicationCopyService;

    @Autowired
    private IAccompanyingCopyService accompanyingCopyService;

    @Autowired
    private IImageBaseService imageBaseService;

    @Override
    public ReservationApplicationDTO getDetailsById(Integer id) {
        ReservationApplication reservationApplication = baseMapper.selectById(id);
        ReservationApplicationDTO reservationApplicationDTO = new ReservationApplicationDTO();
        BeanUtils.copyProperties(reservationApplication, reservationApplicationDTO);

        if (StringUtils.isNotBlank(reservationApplicationDTO.getFacePhoto())) {
            reservationApplicationDTO.setFacePhoto(fileView + reservationApplicationDTO.getFacePhoto());
        }
        //单位名称
        Institution institution = iInstitutionService.getById(reservationApplicationDTO.getRespondentInstitutionId());
        reservationApplicationDTO.setRespondentInstitutionName(institution.getInstitutionName());

        //到访类型
        VisitType visitType = visitTypeService.getById(reservationApplicationDTO.getVisitTypeId());
        if (null != visitType) {
            reservationApplicationDTO.setVisitTypeName(visitType.getTypeName());
        }

        List<Accompanying> accompanyingList = new ArrayList<>();
        if (reservationApplication.getAccompanyingStatus().equals(1)) {
            LambdaQueryWrapper<Accompanying> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Accompanying::getReservationApplicationId, id);
            List<Accompanying> list = accompanyingService.list(queryWrapper);

            for (Accompanying accompanying : list) {
                accompanying.setName(AES.nameXx(accompanying.getName()));
                accompanying.setMobile(AES.mobileIdCardHide(accompanying.getMobile()));
                accompanying.setIdentityValue(AES.mobileIdCardHide(accompanying.getIdentityValue()));
            }

            accompanyingList.addAll(list);
        }
        reservationApplicationDTO.setName(AES.nameXx(reservationApplicationDTO.getName()));
        reservationApplicationDTO.setMobile(AES.mobileIdCardHide(reservationApplicationDTO.getMobile()));
        reservationApplicationDTO.setIdentityValue(AES.mobileIdCardHide(reservationApplicationDTO.getIdentityValue()));
        reservationApplicationDTO.setRespondentName(AES.nameXx(reservationApplicationDTO.getRespondentName()));
        reservationApplicationDTO.setRespondentMobile(AES.mobileIdCardHide(reservationApplicationDTO.getRespondentMobile()));

        reservationApplicationDTO.setAccompanyingList(accompanyingList);

        return reservationApplicationDTO;
    }

    @Override
    public ReservationApplicationCountVO listApplication(Page<ReservationApplication> page, LambdaQueryWrapper<ReservationApplication> queryWrapper,
                                                         Integer applicationStatus,Integer timeType) {

        LambdaQueryWrapper<ReservationApplication> arrivals = queryWrapper.clone();
        LambdaQueryWrapper<ReservationApplication> notArrivals = queryWrapper.clone();

        if (applicationStatus == 2) {
            queryWrapper.eq(ReservationApplication::getStatus, 2);
        } else if (applicationStatus == 3) {
            queryWrapper.eq(ReservationApplication::getStatus, 3);
        }

        if (timeType == 3){
            queryWrapper.orderByAsc(ReservationApplication::getVisitDate);
        }else {
            queryWrapper.orderByDesc(ReservationApplication::getId);
        }


        IPage<ReservationApplication> pageList = this.page(page, queryWrapper);

        Page<ReservationApplicationVO> voPage = new Page<>();
        BeanUtils.copyProperties(pageList, voPage);

        List<ReservationApplicationVO> reservationApplicationVOS = VisitorBeanUtils.convertList2List(pageList.getRecords(), ReservationApplicationVO.class);
        voPage.setRecords(reservationApplicationVOS);

        if (CollectionUtils.isNotEmpty(reservationApplicationVOS)) {
            for (ReservationApplicationVO reservationApplicationVO : reservationApplicationVOS) {
                LambdaQueryWrapper<Accompanying> accompanyingLambdaQueryWrapper = new LambdaQueryWrapper<>();
                accompanyingLambdaQueryWrapper.eq(Accompanying::getReservationApplicationId, reservationApplicationVO.getId());
                int count = accompanyingService.count(accompanyingLambdaQueryWrapper);
                reservationApplicationVO.setAccompanyingCount(count);
                if (StringUtils.isNotBlank(reservationApplicationVO.getNumberPlate())) {
                    reservationApplicationVO.setAccessMethod("车辆");
                } else {
                    reservationApplicationVO.setAccessMethod("人员");
                }
                reservationApplicationVO.setName(AES.nameXx(reservationApplicationVO.getName()));
                reservationApplicationVO.setMobile(AES.mobileIdCardHide(reservationApplicationVO.getMobile()));
                reservationApplicationVO.setIdentityValue(AES.mobileIdCardHide(reservationApplicationVO.getIdentityValue()));
                reservationApplicationVO.setRespondentName(AES.nameXx(reservationApplicationVO.getRespondentName()));
            }
        }


        arrivals.eq(ReservationApplication::getStatus, 3);
        int arrivalsCount = this.count(arrivals);


        notArrivals.eq(ReservationApplication::getStatus, 2);
        int notArrivalsCount = this.count(notArrivals);

        ReservationApplicationCountVO reservationApplicationCountVO = new ReservationApplicationCountVO();
        reservationApplicationCountVO.setPage(voPage);
        reservationApplicationCountVO.setArrivalsCount(arrivalsCount);
        reservationApplicationCountVO.setNotArrivalsCount(notArrivalsCount);
        reservationApplicationCountVO.setCount(arrivalsCount + notArrivalsCount);

        return reservationApplicationCountVO;
    }

    @Override
    public List<ReservationApplicationVO> listApplicationByComingSoon(Integer size) {
        List<ReservationApplicationVO> reservationApplicationVOS = new ArrayList<>();

        LambdaQueryWrapper<ReservationApplication> queryWrapper = new LambdaQueryWrapper<>();

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if (!AuthorityEnum.ONE_USER.getIndex().equals(sysUser.getAuthority())) {
            queryWrapper.in(ReservationApplication::getRespondentInstitutionId, AES.integerList(sysUser.getInstitutionId()));
        }

        queryWrapper.eq(ReservationApplication::getStatus, 2);
        queryWrapper.lt(ReservationApplication::getVisitDate, DateUtils.getBeforeHour(new Date(), 3));
        queryWrapper.ge(ReservationApplication::getVisitDate, DateUtils.getStartTime());
        queryWrapper.orderByDesc(ReservationApplication::getVisitDate);
        queryWrapper.last("limit " + size);


        List<ReservationApplication> reservationApplications = baseMapper.selectList(queryWrapper);
        //        //统计并赋值
        countAccompanying(reservationApplications, reservationApplicationVOS);

        return reservationApplicationVOS;
    }


    @Override
    public List<ReservationApplicationVO> listApplicationByRealTime(Integer size) {
        List<ReservationApplicationVO> reservationApplicationVOS = new ArrayList<>();

        LambdaQueryWrapper<ReservationApplication> queryWrapper = new LambdaQueryWrapper<>();

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if (!AuthorityEnum.ONE_USER.getIndex().equals(sysUser.getAuthority())) {
            queryWrapper.in(ReservationApplication::getRespondentInstitutionId, AES.integerList(sysUser.getInstitutionId()));
        }

        queryWrapper.eq(ReservationApplication::getStatus, 3);
        queryWrapper.ge(ReservationApplication::getArrivalsTime, DateUtils.getStartTime());
        queryWrapper.orderByDesc(ReservationApplication::getArrivalsTime);
        queryWrapper.last("limit " + size);

        List<ReservationApplication> reservationApplications = baseMapper.selectList(queryWrapper);
        //统计并赋值
        countAccompanying(reservationApplications, reservationApplicationVOS);

        return reservationApplicationVOS;
    }

    /**
     * 统计并赋值
     *
     * @param reservationApplications
     * @param reservationApplicationVOS
     */
    private void countAccompanying(List<ReservationApplication> reservationApplications, List<ReservationApplicationVO> reservationApplicationVOS) {
        if (CollectionUtils.isNotEmpty(reservationApplications)) {
            for (ReservationApplication reservationApplication : reservationApplications) {
                ReservationApplicationVO reservationApplicationVO = new ReservationApplicationVO();
                BeanUtils.copyProperties(reservationApplication, reservationApplicationVO);

                LambdaQueryWrapper<Accompanying> accompanyingLambdaQueryWrapper = new LambdaQueryWrapper<>();
                accompanyingLambdaQueryWrapper.eq(Accompanying::getReservationApplicationId, reservationApplication.getId());
                int count = accompanyingService.count(accompanyingLambdaQueryWrapper);
                reservationApplicationVO.setAccompanyingCount(count);

                reservationApplicationVO.setName(AES.nameXx(reservationApplicationVO.getName()));
                reservationApplicationVO.setMobile(AES.mobileIdCardHide(reservationApplicationVO.getMobile()));
                reservationApplicationVO.setIdentityValue(AES.mobileIdCardHide(reservationApplicationVO.getIdentityValue()));
                reservationApplicationVO.setRespondentName(AES.nameXx(reservationApplicationVO.getRespondentName()));

                reservationApplicationVOS.add(reservationApplicationVO);
            }
        }
    }

    private void check(Accompanying accompanying) {

        if (IdentityTypeEnum.IDENTITY_CARD.getIndex().equals(accompanying.getIdentityType())) {
            if (!RegexUtils.checkIdCard(accompanying.getIdentityValue())) {
                throw new JeecgBootException("请输入正确的身份证号：" + accompanying.getName());
            }
        } else {
            if (!RegexUtils.checkPassPort(accompanying.getIdentityValue())) {
                throw new JeecgBootException("请输入护照号：" + accompanying.getName());
            }
        }


        if (!RegexUtils.checkMobile(accompanying.getMobile())) {
            throw new JeecgBootException("请输入正确的手机号：" + accompanying.getName());
        }

        if (StringUtils.isNotBlank(accompanying.getNumberPlate()) &&
                !RegexUtils.checkNumberPlate(accompanying.getNumberPlate())) {
            throw new JeecgBootException("请输入正确的车牌：" + accompanying.getNumberPlate());
        }


        Map<String, String> map = new HashMap<>(16);
        map.put("identityValue", accompanying.getIdentityValue());
        map.put("identityType", IdentityTypeEnum.getName(accompanying.getIdentityType()));
        map.put("name", accompanying.getName());
        map.put("mobile", accompanying.getMobile());
        map.put("token", VisitorConstants.token);
        map.put("timestamp", String.valueOf(DateUtils.getMillis()));
        String sign = SignUtils.createSign(map, VisitorConstants.key);
        map.put("sign", sign);

//        String connectResult = HttpClientUtil.sendHttpPost(JSON.toJSONString(map), VisitorConstants.URL);
//
//        JSONObject object = JSONArray.parseObject(connectResult);
//        Integer code = object.containsKey("code") ? Integer.parseInt(object.getString("code")) : -1;
//        if (code.equals(200)) {
//            String data = object.containsKey("data") ? object.getString("data") : null;
//            if (StringUtils.isNotBlank(data)) {
//                JSONObject jsonObject = JSONArray.parseObject(data);
//                String jmt = jsonObject.containsKey("jmt") ? jsonObject.getString("jmt") : null;
//                if ("green".equals(jmt)) {
//                    return;
//                }
//                throw new JeecgBootException("您不是绿码，预约失败");
//            }
//            throw new JeecgBootException("预约失败");
//        }
//        throw new JeecgBootException("预约失败:" + code);
    }


    @Override
    public IndexCountVO indexCount() {


        LambdaQueryWrapper<ReservationApplication> countTotalQuery = new LambdaQueryWrapper<>();
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        List<Integer> list = AES.integerList(sysUser.getInstitutionId());
        if (!AuthorityEnum.ONE_USER.getIndex().equals(sysUser.getAuthority())) {
            countTotalQuery.in(ReservationApplication::getRespondentInstitutionId, list);
        }


        LambdaQueryWrapper<ReservationApplication> arrivalsCountQuery = countTotalQuery.clone();
        LambdaQueryWrapper<ReservationApplication> notArrivalsCountQuery = countTotalQuery.clone();
        LambdaQueryWrapper<ReservationApplication> historyCountQuery = countTotalQuery.clone();

        //预约总数
        countTotalQuery.between(ReservationApplication::getCreateTime, DateUtils.getStartTime(), DateUtils.getEndTime());
        Integer countTotal = baseMapper.selectCount(countTotalQuery);

        //已到访人数
        arrivalsCountQuery.eq(ReservationApplication::getStatus, 3);
        arrivalsCountQuery.between(ReservationApplication::getArrivalsTime, DateUtils.getStartTime(), DateUtils.getEndTime());
        Integer arrivalsCount = baseMapper.selectCount(arrivalsCountQuery);

        //未到访人数
        notArrivalsCountQuery.in(ReservationApplication::getStatus, 2, 4);
        notArrivalsCountQuery.between(ReservationApplication::getVisitDate, DateUtils.getStartTime(), DateUtils.getEndTime());
        Integer notArrivals = baseMapper.selectCount(notArrivalsCountQuery);

        //历史总数
        historyCountQuery.eq(ReservationApplication::getStatus, 3);
        Integer historyCount = baseMapper.selectCount(historyCountQuery);

        //车辆进出总数
        Integer carCount;
        Integer userCount;
        if (!AuthorityEnum.ONE_USER.getIndex().equals(sysUser.getAuthority())) {
            carCount = visitorAccessreService.toDayCarCount(list,1);
            userCount = visitorAccessreService.toDayCarCount(list,2);
        } else {
            carCount = visitorAccessreService.toDayCarCount(null,1);
            userCount = visitorAccessreService.toDayCarCount(null,2);
        }

        IndexCountVO indexCountVO = new IndexCountVO();
        indexCountVO.setArrivalsCount(arrivalsCount);
        indexCountVO.setNotArrivalsCount(notArrivals);
        indexCountVO.setHistoryCount(historyCount);
        indexCountVO.setCarCount(carCount);
        indexCountVO.setUserCount(userCount);

        return indexCountVO;
    }


    @Override
    public List<Map<String, String>> indexVisitorAnalysis(Integer type,Integer institutionId) {
        List<Map<String, String>> mapList = new ArrayList<>();
        Date time = DateUtils.getEndTimeByDay(new Date(), -1);

        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();

        if (type == 1) {
            List<Date> dates = DateUtils.dateSplit(DateUtils.getBeforeDay(time, 7), time);

            for (int i = 8; i <= 18; i++) {
                LambdaQueryWrapper<ReservationApplication> arrivalsCountQuery = getReservationApplicationLambdaQueryWrapper(institutionId, sysUser);

                Map<String, String> map = new HashMap<>(16);
                map.put("time", i + ":00");

                //时间条件
                arrivalsCountQuery.apply("(deleted=1");
                for (int j = 0; j < dates.size(); j++) {
                    Date startTimeByHour = DateUtils.getStartTimeByHour(dates.get(j), i);
                    Date endTimeByHour = DateUtils.getEndTimeByHour(dates.get(j), i);

                    if (j == 0) {
                        arrivalsCountQuery.between(ReservationApplication::getVisitDate, startTimeByHour, endTimeByHour);
                    } else {
                        arrivalsCountQuery.or().between(ReservationApplication::getVisitDate, startTimeByHour, endTimeByHour);
                    }
                }

                arrivalsCountQuery.apply(" deleted=1)");

                LambdaQueryWrapper<ReservationApplication> notArrivalsCountQuery = arrivalsCountQuery.clone();
                //已到人数
                arrivalsCountQuery.eq(ReservationApplication::getStatus, ApplicationStatusEnum.FWCG.getIndex());
                Integer arrivalsCount = baseMapper.selectCount(arrivalsCountQuery);

                //未到人数
                notArrivalsCountQuery.eq(ReservationApplication::getStatus, ApplicationStatusEnum.SQTG.getIndex());
                Integer notArrivalsCount = baseMapper.selectCount(notArrivalsCountQuery);

                map.put("notArrivalsCount", notArrivalsCount.toString());
                map.put("arrivalsCount", arrivalsCount.toString());

                mapList.add(map);
            }

        } else if (type == 2) {
            List<Date> dates = DateUtils.dateSplit(DateUtils.getBeforeDay(time, 30), time);
            Collections.reverse(dates);
            for (Date date : dates) {
                LambdaQueryWrapper<ReservationApplication> arrivalsCountQuery = getReservationApplicationLambdaQueryWrapper(institutionId, sysUser);
                Date startTime = DateUtils.getStartTime(date);
                Date endTime = DateUtils.getEndTime(date);

                Map<String, String> map = new HashMap<>(16);
                map.put("time", DateUtils.getMonthDayStr(date));

                arrivalsCountQuery.between(ReservationApplication::getVisitDate, startTime, endTime);

                LambdaQueryWrapper<ReservationApplication> notArrivalsCountQuery = arrivalsCountQuery.clone();
                //已到人数
                arrivalsCountQuery.eq(ReservationApplication::getStatus, ApplicationStatusEnum.FWCG.getIndex());
                Integer arrivalsCount = baseMapper.selectCount(arrivalsCountQuery);

                //未到人数
                notArrivalsCountQuery.eq(ReservationApplication::getStatus, ApplicationStatusEnum.SQTG.getIndex());
                Integer notArrivalsCount = baseMapper.selectCount(notArrivalsCountQuery);

                map.put("notArrivalsCount", notArrivalsCount.toString());
                map.put("arrivalsCount", arrivalsCount.toString());

                mapList.add(map);
            }
        } else {
            Date date = DateUtils.getDate();
            for (int i = 12; i >= 1; i--) {
                LambdaQueryWrapper<ReservationApplication> arrivalsCountQuery = getReservationApplicationLambdaQueryWrapper(institutionId, sysUser);
                Date startTimeByMonth = DateUtils.getStartTimeByMonth(date, -i);
                Date endTimeByMonth = DateUtils.getEndTimeByMonth(date, -i);

                Map<String, String> map = new HashMap<>(16);
                map.put("time", DateUtils.getYearMonthStr(startTimeByMonth));

                arrivalsCountQuery.between(ReservationApplication::getVisitDate, startTimeByMonth, endTimeByMonth);

                LambdaQueryWrapper<ReservationApplication> notArrivalsCountQuery = arrivalsCountQuery.clone();
                //已到人数
                arrivalsCountQuery.eq(ReservationApplication::getStatus, ApplicationStatusEnum.FWCG.getIndex());
                Integer arrivalsCount = baseMapper.selectCount(arrivalsCountQuery);

                //未到人数
                notArrivalsCountQuery.eq(ReservationApplication::getStatus, ApplicationStatusEnum.SQTG.getIndex());
                Integer notArrivalsCount = baseMapper.selectCount(notArrivalsCountQuery);

                map.put("notArrivalsCount", notArrivalsCount.toString());
                map.put("arrivalsCount", arrivalsCount.toString());

                mapList.add(map);
            }
        }

        return mapList;
    }

    private LambdaQueryWrapper<ReservationApplication> getReservationApplicationLambdaQueryWrapper(Integer institutionId, LoginUser sysUser) {
        LambdaQueryWrapper<ReservationApplication> arrivalsCountQuery = new LambdaQueryWrapper<>();

        if (null != institutionId) {
            arrivalsCountQuery.eq(ReservationApplication::getRespondentInstitutionId, institutionId);
        } else if (!AuthorityEnum.ONE_USER.getIndex().equals(sysUser.getAuthority())) {
            arrivalsCountQuery.in(ReservationApplication::getRespondentInstitutionId, AES.integerList(sysUser.getInstitutionId()));
        }
        return arrivalsCountQuery;
    }


    @Override
    public List<Map<String, String>> indexVisitorAnalysisByDay(Integer institutionId) {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        List<Map<String, String>> mapList = new ArrayList<>();
        Date date = DateUtils.getDate();

        for (int i = 8; i <= 18; i++) {

            Map<String, String> map = new HashMap<>(16);
            map.put("time", i + ":00");

            Date startTimeByHour = DateUtils.getStartTimeByHour(date, i);
            Date endTimeByHour = DateUtils.getEndTimeByHour(date, i);

            LambdaQueryWrapper<ReservationApplication> arrivalsCountQuery = getReservationApplicationLambdaQueryWrapper(institutionId, sysUser);

            //时间条件
            arrivalsCountQuery.between(ReservationApplication::getVisitDate, startTimeByHour, endTimeByHour);

            LambdaQueryWrapper<ReservationApplication> notArrivalsCountQuery = arrivalsCountQuery.clone();
            //已到人数
            arrivalsCountQuery.eq(ReservationApplication::getStatus, ApplicationStatusEnum.FWCG.getIndex());
            Integer arrivalsCount = baseMapper.selectCount(arrivalsCountQuery);

            //未到人数
            notArrivalsCountQuery.eq(ReservationApplication::getStatus, ApplicationStatusEnum.SQTG.getIndex());
            Integer notArrivalsCount = baseMapper.selectCount(notArrivalsCountQuery);

            map.put("notArrivalsCount", notArrivalsCount.toString());
            map.put("arrivalsCount", arrivalsCount.toString());

            mapList.add(map);
        }

        return mapList;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void dataTransmission(List<ReservationApplicationDTO> reservationApplicationDTOs) {

        if (CollectionUtils.isEmpty(reservationApplicationDTOs)) {
            return;
        }

        Date date = DateUtils.getDate();
        List<PushRecord> pushRecords = new ArrayList();
        for (ReservationApplicationDTO reservationApplicationDTO : reservationApplicationDTOs) {

            if (StringUtils.isNotBlank(reservationApplicationDTO.getFacePhoto())) {
                String upload1 = UploadUtil.upload(uploadUrl, reservationApplicationDTO.getFacePhoto());
                reservationApplicationDTO.setFacePhoto(upload1);
            }
            //添加拜访主记录
            ReservationApplication reservationApplication = new ReservationApplication();

            BeanUtils.copyProperties(reservationApplicationDTO, reservationApplication);

            reservationApplication.setStatus(ApplicationStatusEnum.SQTG.getIndex());
            reservationApplication.setPushStatus(0);
            reservationApplication.setCreateTime(date);
            reservationApplication.setUpdateTime(date);
            //todo 暂时注释
            checkVisitor(reservationApplication);

            baseMapper.insert(reservationApplication);

            Institution byId = iInstitutionService.getById(reservationApplicationDTO.getRespondentInstitutionId());
            List<Device> devices = deviceService.listDeviceByInstitutionId(reservationApplicationDTO.getRespondentInstitutionId());


            for (Device device : devices) {
                PushRecord record = new PushRecord();
                record.setReservationApplicationId(reservationApplication.getId());
                record.setInstitutionId(reservationApplication.getRespondentInstitutionId());
                record.setInstitutionCode(byId.getCode());
                record.setDeviceId(device.getId());
                record.setDeviceName(device.getDeviceName());
                record.setDeviceCode(device.getDeviceCode());
                record.setDeviceIp(device.getDeviceIp());
                record.setDevicePort(device.getDevicePort());
                record.setVisitDate(reservationApplicationDTO.getVisitDate());
                record.setPushStatus(0);
                record.setCreateTime(date);
                record.setUpdateTime(date);
                pushRecords.add(record);
            }

            //添加随行记录
            List<Accompanying> accompanyingList = reservationApplicationDTO.getAccompanyingList();
            if (CollectionUtils.isEmpty(accompanyingList)) {
                continue;
            }
            for (Accompanying save : accompanyingList) {
                if (StringUtils.isNotBlank(save.getFacePhoto())) {
                    String s = UploadUtil.upload(uploadUrl, save.getFacePhoto());
                    save.setFacePhoto(s);
                }
                save.setReservationApplicationId(reservationApplication.getId());
                save.setDeleted(1);
                save.setCreateTime(date);
                save.setUpdateTime(date);
            }
            accompanyingService.saveBatch(accompanyingList);

        }

        pushRecordService.saveBatch(pushRecords);

        try {
            //已设备编码分组
            Map<String, List<PushRecord>> collect = pushRecords.stream().collect(Collectors.groupingBy(e -> e.getDeviceCode()));

            ExecutorService executor = Executors.newFixedThreadPool(5);
            collect.forEach((e, k) ->
                    executor.submit(() ->
                            sjyService.pushApplication(k)
            ));
        } catch (Exception e) {
            log.info("[{}] error:", e.getMessage());
        }

    }

    @Override
    public void dataTransmission() {

        //查询出没有推送的
        LambdaQueryWrapper<ReservationApplicationCopy> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ReservationApplicationCopy::getPushStatus, 0);
        queryWrapper.eq(ReservationApplicationCopy::getStatus, ApplicationStatusEnum.SQTG.getIndex());
        queryWrapper.ge(ReservationApplicationCopy::getVisitDate, DateUtils.getStartTime());

        List<ReservationApplicationCopy> reservationApplications = reservationApplicationCopyService.list(queryWrapper);

        Date date = DateUtils.getDate();
        List<PushRecord> pushRecords = new ArrayList();
        for (ReservationApplicationCopy reservationApplicationCopy : reservationApplications) {
            ReservationApplication saveEntity = new ReservationApplication();
            BeanUtils.copyProperties(reservationApplicationCopy, saveEntity);

            ImageBase byId = imageBaseService.getById(reservationApplicationCopy.getId());
            if (null != byId && StringUtils.isNotBlank(byId.getImageBase())) {
                String upload1 = UploadUtil.upload(uploadUrl, byId.getImageBase());
                saveEntity.setFacePhoto(upload1);
            }
            //添加拜访主记录
            saveEntity.setStatus(ApplicationStatusEnum.SQTG.getIndex());
            saveEntity.setPushStatus(0);
            saveEntity.setCreateTime(date);
            saveEntity.setUpdateTime(date);
            //todo 暂时注释
            checkVisitor(saveEntity);

            baseMapper.insert(saveEntity);

            Institution institution = iInstitutionService.getById(saveEntity.getRespondentInstitutionId());
            List<Device> devices = deviceService.listDeviceByInstitutionId(saveEntity.getRespondentInstitutionId());

            for (Device device : devices) {
                PushRecord record = new PushRecord();
                record.setReservationApplicationId(saveEntity.getId());
                record.setInstitutionId(saveEntity.getRespondentInstitutionId());
                record.setInstitutionCode(institution.getCode());
                record.setDeviceId(device.getId());
                record.setDeviceName(device.getDeviceName());
                record.setDeviceCode(device.getDeviceCode());
                record.setDeviceIp(device.getDeviceIp());
                record.setDevicePort(device.getDevicePort());
                record.setVisitDate(saveEntity.getVisitDate());
                record.setPushStatus(0);
                record.setIsCarStatus(saveEntity.getIsCarStatus());
                record.setCreateTime(date);
                record.setUpdateTime(date);
                pushRecords.add(record);
            }

            //添加随行记录
            if (ACCOMPANYING_STATUS_YES.equals(saveEntity.getAccompanyingStatus())){
                List<AccompanyingCopy> accompanyingList = accompanyingCopyService.listAccompanyingByApplicationId(reservationApplicationCopy.getId());

                if (CollectionUtils.isEmpty(accompanyingList)) {
                    continue;
                }
                List<Accompanying> accompanyings =new ArrayList();

                for (AccompanyingCopy save : accompanyingList) {
                    Accompanying accompanying = new Accompanying();
                    BeanUtils.copyProperties(save,accompanying);
                    accompanying.setReservationApplicationId(saveEntity.getId());
                    accompanying.setDeleted(1);
                    accompanying.setCreateTime(date);
                    accompanying.setUpdateTime(date);
                    accompanyings.add(accompanying);
                }
                accompanyingService.saveBatch(accompanyings);
            }
        }

        //插入推送表
        pushRecordService.saveBatch(pushRecords);

        //修改外侧数据库推送状态
        List<Integer> reservationApplicationCopyIds = reservationApplications.stream().map(ReservationApplicationCopy::getId).collect(Collectors.toList());
        reservationApplicationCopyService.updatePushStatus(reservationApplicationCopyIds);

        try {
            //已设备编码分组
            Map<String, List<PushRecord>> collect = pushRecords.stream().filter(
                    e -> e.getVisitDate().compareTo(DateUtils.getStartTime()) < 0).collect(Collectors.groupingBy(e -> e.getDeviceCode()));

            ExecutorService executor = Executors.newFixedThreadPool(5);
            collect.forEach((e, k) ->
                    executor.submit(() ->
                            sjyService.pushApplication(k)
                    ));
        } catch (Exception e) {
            log.info("[{}] error:", e.getMessage());
        }

    }

    /**
     * 校验是否为警员或者为重点人员
     * @param reservationApplication
     */
    private void checkVisitor(ReservationApplication reservationApplication) {
        Integer visitorIdentity = 1;
        if (policeService.getPoliceByIdentityValue(reservationApplication.getIdentityValue())) {
            visitorIdentity = 3;
        } else if (null != keyPersonnelService.getById(reservationApplication.getIdentityValue())) {
            visitorIdentity = 4;
        } else {
            visitorIdentity = 1;
        }
        reservationApplication.setVisitorIdentity(visitorIdentity);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveReservationByDevice(VisitorReservationDTO visitorReservationDTO) {


        ReservationApplication reservationApplication = new ReservationApplication();
        BeanUtils.copyProperties(visitorReservationDTO, reservationApplication);
        Institution institutionByCode = iInstitutionService.getInstitutionByCode(visitorReservationDTO.getInstitutionCode());
        if (null == institutionByCode) {
            throw new JeecgBootException("该事业编码" + visitorReservationDTO.getInstitutionCode() + "不存在");
        }
        Device deviceByCodeAndInstitutionId = deviceService.getDeviceByCodeAndInstitutionId(visitorReservationDTO.getDeviceCode(), institutionByCode.getId());
        if (deviceByCodeAndInstitutionId == null) {
            throw new JeecgBootException("该设备未注册到该单位");
        }


        //1 登记已进入 2：登记未进入        已进访问成功，未进访问提交成功
        if (visitorReservationDTO.getRegistrationStatus().equals(1)) {
            reservationApplication.setStatus(ApplicationStatusEnum.FWCG.getIndex());
            reservationApplication.setArrivalsTime(visitorReservationDTO.getVisitDate());
        } else {
            reservationApplication.setStatus(ApplicationStatusEnum.SQTG.getIndex());
        }

        //解密并校验身份号
        reservationApplication.setIdentityValue(AESSJY.AESjiemi(reservationApplication.getIdentityValue()));
        if (IdentityTypeEnum.IDENTITY_CARD.getIndex().equals(reservationApplication.getIdentityType())) {
            if (!RegexUtils.checkIdCard(reservationApplication.getIdentityValue())) {
                throw new JeecgBootException("请输入正确的身份证号：" + reservationApplication.getName());
            }
        }

        //解密并校验拜访人手机号
        reservationApplication.setMobile(AESSJY.AESjiemi(reservationApplication.getMobile()));
        if (!RegexUtils.checkMobile(reservationApplication.getMobile())) {
            throw new JeecgBootException("请输入正确的拜访人手机号");
        }


        //解密并校验被拜访人手机号
        reservationApplication.setRespondentMobile(AESSJY.AESjiemi(reservationApplication.getRespondentMobile()));
        if (!RegexUtils.checkMobile(reservationApplication.getRespondentMobile())) {
            throw new JeecgBootException("请输入正确的被拜访人手机号");
        }


        if (StringUtils.isNotBlank(reservationApplication.getNumberPlate())) {
            reservationApplication.setNumberPlate(AESSJY.AESjiemi(reservationApplication.getNumberPlate()));
        }

        //通过身份证判断男女
        if (visitorReservationDTO.getSex() == null && IdentityTypeEnum.IDENTITY_CARD.getIndex().equals(reservationApplication.getIdentityType())) {
            int sexFromIdCard = RegexUtils.getSexFromIdCard(visitorReservationDTO.getIdentityValue());
            reservationApplication.setSex(sexFromIdCard);
        }

        reservationApplication.setRespondentInstitutionId(institutionByCode.getId());
        String facePhoto = UploadUtil.upload(uploadUrl, visitorReservationDTO.getFacePhoto());
        reservationApplication.setFacePhoto(facePhoto);
        Date date = DateUtils.getDate();
        reservationApplication.setCreateTime(date);
        reservationApplication.setUpdateTime(date);

        //todo 暂时注释
        checkVisitor(reservationApplication);

        reservationApplication.setVisitorIdentity(1);
        reservationApplication.setAccompanyingStatus(0);
        reservationApplication.setReservationChannel(2);
        save(reservationApplication);
        return "";
    }

    @Override
    public ReservationApplicationVO getNewApplicationByOpenId(String openId) {
        LambdaQueryWrapper<ReservationApplication> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ReservationApplication::getOpenId, openId);
        queryWrapper.orderByDesc(ReservationApplication::getId);
        queryWrapper.last("limit 1");

        ReservationApplication reservationApplication = baseMapper.selectOne(queryWrapper);

        ReservationApplicationVO reservationApplicationVO = new ReservationApplicationVO();
        if (null != reservationApplication) {
            BeanUtils.copyProperties(reservationApplication, reservationApplicationVO);
        }

        return reservationApplicationVO;
    }

    @Override
    public ReservationApplicationVO getApplicationByPushStatus(String openId) {
        return null;
    }


    @Override
    public void updateByArrivals(String identityValue, Date date) {

        Date startTime = DateUtils.getStartTime(date);
        Date endTime = DateUtils.getEndTime(date);


        LambdaQueryWrapper<ReservationApplication> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(ReservationApplication::getId);
        queryWrapper.eq(ReservationApplication::getIdentityValue, identityValue);
        queryWrapper.between(ReservationApplication::getVisitDate, startTime, endTime);

        List<ReservationApplication> reservationApplications = baseMapper.selectList(queryWrapper);

        if (CollectionUtils.isEmpty(reservationApplications)) {
            return;
        }

        for (ReservationApplication reservationApplication : reservationApplications) {
            reservationApplication.setArrivalsTime(date);
            reservationApplication.setStatus(ApplicationStatusEnum.FWCG.getIndex());
        }

        updateBatchById(reservationApplications);
    }
}
